package com.example.demo.service.impl;

import com.example.demo.dao.TaskMapper;
import com.example.demo.exception.QuartzException;
import com.example.demo.models.TaskEntity;
import com.example.demo.service.ITaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashSet;
import java.util.List;

/**
 * TriggerState
 * WAITING, ACQUIRED, COMPLETE, PAUSED, BLOCKED, PAUSED_BLOCKED, ERROR
 */
@Slf4j
@Service
public class TaskServiceImpl implements ITaskService {

    private final TaskMapper taskDao;
    private final Scheduler scheduler;

    public TaskServiceImpl(TaskMapper taskDao, Scheduler scheduler) {
        this.taskDao = taskDao;
        this.scheduler = scheduler;
    }

    /**
     * @param info
     * @return
     * @// TODO: 2018/6/8 保存定时任务
     */
    @Override
    @SuppressWarnings("unchecked")
    public Boolean addTask(TaskEntity info) {
        try {
            scheduler.start();
            String jobName = info.getJobName(),
                    jobGroup = info.getJobGroup(),
                    cronExpression = info.getCronExpression(),
                    jobDescription = info.getJobDescription();
            if (checkExists(jobName, jobGroup)) {
                throw new QuartzException(String.format("Job已经存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));
            }
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(info.getJobClass());
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(jobDescription).withSchedule(scheduleBuilder).forJob(jobDetail).startNow().build();
            scheduler.scheduleJob(jobDetail, trigger);
            log.info("创建任务成功！jobName = {}", jobName);
            return true;
        } catch (SchedulerException | ClassNotFoundException e) {
            throw new QuartzException("类名不存在或执行表达式错误");
        }
    }

    /**
     * @param taskEntity
     * @return
     * @// TODO: 2018/6/8 开始定时任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resumeTask(TaskEntity taskEntity) {
        try {
            scheduler.start();
            scheduler.resumeJob(JobKey.jobKey(taskEntity.getJobName(), taskEntity.getJobGroup()));
            log.info("开始定时任务！jobName = {}", taskEntity.getJobName());
            return true;
        } catch (Exception e) {
            throw new QuartzException("FAILED");
        }
    }

    /**
     * @return
     * @// TODO: 2018/6/5  查询job
     */
    @Override
    @Transactional(readOnly = true)
    public List<TaskEntity> findTaskList(TaskEntity taskEntity) {
        log.info("查询任务列表！");
        return taskDao.findTaskList(taskEntity);
    }

    /**
     * 修改定时任务
     *
     * @param info
     */
    @Override
    public Boolean updateTask(TaskEntity info) {
        try {
            scheduler.start();
            String jobName = info.getJobName(),
                    jobGroup = info.getJobGroup(),
                    cronExpression = info.getCronExpression(),
                    jobDescription = info.getJobDescription(),
                    createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
            if (!checkExists(jobName, jobGroup)) {
                throw new QuartzException(String.format("Job不存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));
            }
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = new JobKey(jobName, jobGroup);
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            jobDetail.getJobBuilder().withDescription(jobDescription);
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(cronScheduleBuilder).forJob(jobDetail).build();
            HashSet<Trigger> triggerSet = new HashSet<>();
            triggerSet.add(cronTrigger);
            scheduler.scheduleJob(jobDetail, triggerSet, true);
            log.info("更新定时任务！jobName = {}", jobName);
            return true;
        } catch (SchedulerException e) {
            throw new QuartzException("类名不存在或执行表达式错误");
        }
    }

    /**
     * @param taskEntity
     * @// TODO: 2018/6/1 停止任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean pauseTask(TaskEntity taskEntity) {
        try {
            scheduler.start();
            TriggerKey triggerKey = TriggerKey.triggerKey(taskEntity.getJobName(), taskEntity.getJobGroup());
            if (checkExists(taskEntity.getJobName(), taskEntity.getJobGroup())) {
                scheduler.pauseTrigger(triggerKey);
            }
            log.info("停止任务！jobName = {}", taskEntity.getJobName());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new QuartzException(e.getMessage());
        }
    }

    /**
     * @param taskEntity
     * @return
     * @// TODO: 2018/6/7 删除任务
     */
    @Override
    public Boolean deleteTask(TaskEntity taskEntity) {
        try {
            scheduler.start();
            TriggerKey triggerKey = TriggerKey.triggerKey(taskEntity.getJobName(), taskEntity.getJobGroup());
            if (checkExists(taskEntity.getJobName(), taskEntity.getJobGroup())) {
                scheduler.pauseTrigger(triggerKey);
                scheduler.unscheduleJob(triggerKey);
                scheduler.deleteJob(JobKey.jobKey(taskEntity.getJobName(), taskEntity.getJobGroup()));
                log.info("删除任务！jobName = {}", taskEntity.getJobName());
                return true;
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new QuartzException(e.getMessage());
        }
        return false;
    }

    /**
     * 验证是否存在
     *
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    private boolean checkExists(String jobName, String jobGroup) throws SchedulerException {
        scheduler.start();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        return scheduler.checkExists(triggerKey);
    }
}
